package com.ruoyi.pad.controller;

import cn.hutool.core.map.MapUtil;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.annotation.RateLimiter;
import com.ruoyi.common.code.ServiceHttpCode;
import com.ruoyi.common.code.SystemHttpCode;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.utils.qrKey.CacheQrKeyUtils;
import com.ruoyi.pad.domain.DeviceRegister;
import com.ruoyi.pad.domain.KyBaseMotor;
import com.ruoyi.pad.domain.KyPadInfo;
import com.ruoyi.pad.domain.PadMotorPadToServerDTO;
import com.ruoyi.pad.service.IDeskAppService;
import com.ruoyi.pad.service.IKyBaseMotorService;
import com.ruoyi.pad.service.IKyDeviceInfoService;
import com.ruoyi.pad.service.IKyPadInfoService;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.ISysDictDataService;
import com.ruoyi.system.service.ISysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/pad/desk")
@Api(tags = "平板数据上传通用接口")
public class PadDeskController extends BaseController {

    @Autowired
    private IKyPadInfoService kyPadInfoService;

    @Autowired
    private IDeskAppService deskAppService;

    @Autowired
    private ISysDictDataService sysDictDataService;

    @Autowired
    private ISysDeptService sysDeptService;

    @Autowired
    private ISysUserService sysUserService;

    @Resource
    private IKyBaseMotorService kyBaseMotorService;

    @Autowired
    private IKyDeviceInfoService kyDeviceInfoService;


    @Anonymous
    @RateLimiter
    @GetMapping("/ip/effective")
    public AjaxResult verifyIP() {
        return AjaxResult.success("服务可用");
    }


    /**
     * 查询平台支持的仪器类型
     */
    @Anonymous
    @RateLimiter
    @GetMapping("/device/type")
    public AjaxResult searchDeviceTypeList() {
        List<SysDictData> devTypeList = sysDictDataService.findDevTypeList();
        return AjaxResult.success(devTypeList);
    }


    /**
     * 检查平板是否注册
     * code = 2011, message = "仪器已经注册云平台"
     * code = 2012, message = "仪器还未注册云平台"
     */
    @Anonymous
    @RateLimiter
    @GetMapping("/device/bind/status/{devNum}/{padSn}")
    @ApiOperation(value = "检查平板是否注册")
    public AjaxResult bindStatus( @PathVariable String devNum, @PathVariable String padSn) {
        return kyPadInfoService.haveBind(devNum, padSn) ? new AjaxResult(ServiceHttpCode.BIND_BOUND.getCode(), ServiceHttpCode.BIND_BOUND.getMsg()) : new AjaxResult(ServiceHttpCode.BIND_UNBOUND.getCode(), ServiceHttpCode.BIND_UNBOUND.getMsg());
    }


    /**
     * 检查平板是否存在平台
     * code = 2011, message = "仪器已经注册云平台"
     * code = 2012, message = "仪器还未注册云平台"
     */
    @Anonymous
    @RateLimiter
    @GetMapping("/device/bind/status/{padSn}")
    @ApiOperation(value = "检查平板是否存在平台")
    public AjaxResult bindStatus(  @PathVariable String padSn) {
        return kyPadInfoService.haveBind(padSn) ? new AjaxResult(ServiceHttpCode.BIND_BOUND.getCode(), ServiceHttpCode.BIND_BOUND.getMsg()) : new AjaxResult(ServiceHttpCode.BIND_UNBOUND.getCode(), ServiceHttpCode.BIND_UNBOUND.getMsg());
    }


    /**
     * 扫码注册信息
     * code = 2001, message = "参数错误",
     * code = 2002, message = "仪器已经被注册",
     * code = 2003, message = "平板SN码已注册",
     * code = 2006, message = "KEY错误",
     * code = 2009, message = "仪器注册成功",
     * code = 2010, message = "仪器注册失败",
     */
    @Anonymous
    @RateLimiter
    @PostMapping(value = "/register")
    // TODO: 2023/8/29 未加入通风阻力存在两个平板的处理逻辑
    public AjaxResult scanRegister(@RequestBody DeviceRegister register) {
        if (StringUtils.isEmpty(register.getDevNum())) {
            return AjaxResult.error(ServiceHttpCode.BIND_ERROR_KEY.getCode(), "出厂编码为空");
        }
        if (StringUtils.isEmpty(register.getBindKey())) {
            return AjaxResult.error(ServiceHttpCode.BIND_ERROR_BIND_KEY.getCode(), "BIND-KEY为空");
        }
        if (kyPadInfoService.haveBind(register.getPadSn())) {
            //判断当前平板是否已注册，已注册解绑
            kyPadInfoService.deleteKyPadInfoByPadSn(register.getPadSn());
            //删除当前用户和devNum的仪器信息
            LoginUser loginUser = CacheQrKeyUtils.getQrCache(register.getBindKey());
            kyDeviceInfoService.deleteKyDeviceInfoByDevNum(register.getDevNum(), String.valueOf(loginUser.getUser().getUserId()));
            //return AjaxResult.error(ServiceHttpCode.BIND_PAD_REGISTERED.getCode(), "SN为" + register.getPadSn() + "的平板已经注册，请勿重复操作");
        }
        boolean isRegister = deskAppService.scanRegister(register);

        return isRegister ? new AjaxResult(ServiceHttpCode.BIND_SUCCESS.getCode(), "成功注册") : new AjaxResult(ServiceHttpCode.BIND_FAIL.getCode(), "仪器注册失败");
    }


    /**
     * 影像资料上传接口
     */
    @Anonymous
    @RateLimiter
    @PostMapping("/media/uploads")
    @ApiOperation(value = "影像资料上传接口")
    // TODO: 2023/8/29 影像资料都放在media文件下了，可以更改为根据“deptId”、“appType”分开存放
    public AjaxResult uploadMedia(@RequestPart("files") List<MultipartFile> files, String padSn, String appType) {
        if (!kyPadInfoService.haveBind(padSn)) {
            return AjaxResult.error(ServiceHttpCode.BIND_UNBOUND.getCode(), "非法仪器");
        }
        try {
            return AjaxResult.success(deskAppService.uploadMedia(files, padSn, appType));
        } catch (Exception e) {
            return AjaxResult.error(e.getMessage());
        }
    }


    /**
     * 查询检测员信息库
     * @param padSn      Pad唯一识别码
     * @param libVersion Pad本地用户库版本号
     * code = 2012, message = "平板未绑定"
     * code = 3010, message = "Pad测试员信息库需要更新"
     * code = 3011, message = "Pad测试员信息库不需要更新"
     * @return
     */
    @Anonymous
    @RateLimiter
    @GetMapping("/lib/user/{padSn}/{libVersion}")
    public AjaxResult updateUser(
            @PathVariable("padSn") String padSn,
            @PathVariable("libVersion") Long libVersion) {
        // 根据padSn查询已绑定的平板
        KyPadInfo kyPadInfo = kyPadInfoService.selectKyPadInfoByPadSn(padSn);
        if (kyPadInfo == null) {
            return AjaxResult.error(ServiceHttpCode.BIND_UNBOUND.getCode(), "未注册");
        }

        // 查看用户信息库版本
        Long dbUserV = sysDeptService.selectUserV(kyPadInfo.getDeptId());
        if (libVersion.longValue() < dbUserV.longValue()) {
            List<String> userNameList = sysUserService.selectUserNameList(kyPadInfo.getDeptId());
            Map<String, Object> result = MapUtil.newHashMap();
            // 需要更新的用户信息集合
            result.put("userNameList", userNameList);
            // 数据库中最新的用户信息库版本
            result.put("serverVersion", dbUserV);
            // 平板上的用户信息库版本
            result.put("padVersion", libVersion);
            return new AjaxResult(ServiceHttpCode.USER_LIB_HAVE_NEW, result);
        }

        return new AjaxResult(ServiceHttpCode.USER_LIB_NOT_NEW);
    }

    /**
     * 电机库列表数据查询
     */
    @Anonymous
    @RateLimiter
    @ApiOperation(value = "电机库列表数据查询")
    @PreAuthorize("@ss.hasPermi('pad:motor:list')")
    @GetMapping("/list")
    public TableDataInfo list(KyBaseMotor kyBaseMotor) {
        startPage();
        List<KyBaseMotor> list = kyBaseMotorService.selectKyBaseMotorList(kyBaseMotor);
        return getDataTable(list);
    }


    /**
     * 查询电机库
     *
     * @param padSn      Pad唯一识别码
     * @param libVersion Pad本地电机库
     * code = 2012, message = "未注册仪器"
     * code = 3000, message = "平板需要更新电机库"
     * code = 3001, message = "平板无需更新电机库"
     * @return
     */
    @Anonymous
    @RateLimiter
    @GetMapping("/lib/motor/{padSn}/{libVersion}")
    @ApiOperation(value = "查询电机库")
    public AjaxResult updateMotor(@ApiParam(name="padSn",value="传入json格式",required=true)@PathVariable String padSn, @ApiParam(name="libVersion",value="传入json格式",required=true)@PathVariable Long libVersion) {
        // 根据padSn查询已绑定的平板
        KyPadInfo kyPadInfoEntity = kyPadInfoService.selectKyPadInfoByPadSn(padSn);
        if (kyPadInfoEntity == null) {
            return AjaxResult.error(ServiceHttpCode.BIND_UNBOUND.getCode(), "未注册");
        }
        // 查询数据库电机版本号，每家单位维护一个公共的电机库
        Long dbMotorV = sysDeptService.selectMotorV(kyPadInfoEntity.getDeptId());
        if (libVersion.longValue() < dbMotorV.longValue()) {
            List<KyBaseMotor> motorList = kyBaseMotorService.selectCustomList(kyPadInfoEntity.getDeptId(), kyPadInfoEntity.getUserId());
            Map<String, Object> result = MapUtil.newHashMap();
            // 本单位所有的自定义电机库
            result.put("motorList", motorList);
            // 服务器上的电机库版本
            result.put("serverVersion", dbMotorV);
            // 平板上的电机库版本
            result.put("padVersion", libVersion);
            return new AjaxResult(ServiceHttpCode.MOTOR_LIB_HAVE_NEW.getCode(), "平板需要更新电机库", result);
        }

        return new AjaxResult(ServiceHttpCode.MOTOR_LIB_NOT_NEW.getCode(), "平板无需更新电机库");
    }

    /**
     * 新增本地的电机库数据
     */
    @Transactional
    @PostMapping(value = "/localMotor/create")
    @PreAuthorize("@ss.hasPermi('pad:motor:add')")
    @ApiOperation(value = "新增本地的电机库数据")
    public AjaxResult addLocalMotor(@ApiParam(name="kyBaseMotor",value="传入json格式",required=true) @RequestBody KyBaseMotor kyBaseMotor) {
        //当前电机库版本号加1并同步用户信息
        Long motorV = SecurityUtils.getLoginUser().getUser().getDept().getSyncMotorV() + 1L;
        SysDept sysDept = new SysDept();
        sysDept.setSyncMotorV(motorV);
        sysDept.setDeptId(SecurityUtils.getLoginUser().getUser().getDept().getDeptId());
        sysDeptService.updateDept(sysDept);
        //新增电机库数据
        return AjaxResult.success(kyBaseMotorService.insertKyBaseMotor(kyBaseMotor));

    }

    /**
     * 新增本地的电机库数据
     */
    @Transactional
    @PutMapping(value = "/localMotor/update")
    @PreAuthorize("@ss.hasPermi('pad:motor:update')")
    @ApiOperation(value = "更新本地的电机库数据")
    public AjaxResult updateLocalMotor(@ApiParam(name="kyBaseMotor",value="传入json格式",required=true) @RequestBody KyBaseMotor kyBaseMotor) {
        //当前电机库版本号加1并同步用户信息
        Long motorV = SecurityUtils.getLoginUser().getUser().getDept().getSyncMotorV() + 1L;
        SysDept sysDept = new SysDept();
        sysDept.setSyncMotorV(motorV);
        sysDept.setDeptId(SecurityUtils.getLoginUser().getUser().getDept().getDeptId());
        sysDeptService.updateDept(sysDept);
        //更新电机库数据
        return AjaxResult.success(kyBaseMotorService.updateKyBaseMotor(kyBaseMotor));

    }

    /**
     * 导出电机库数据
     */
    @Log(title = "电机库数据", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    @ApiOperation(value = "导出电机库数据")
    @PreAuthorize("@ss.hasPermi('pad:motor:export')")
    public void export(HttpServletResponse response, KyBaseMotor kyBaseMotor)
    {
        List<KyBaseMotor> list = kyBaseMotorService.selectKyBaseMotorList(kyBaseMotor);
        ExcelUtil<KyBaseMotor> util = new ExcelUtil<>(KyBaseMotor.class);
        util.exportExcel(response, list, "电机库数据");
    }

    /**
     * 删除本地的电机库数据
     */
    @Transactional
    @DeleteMapping(value = "/localMotor/delete/{motorId}")
    @ApiOperation(value = "删除本地的电机库数据")
    @PreAuthorize("@ss.hasPermi('pad:motor:delete')")
    public AjaxResult deleteLocalMotor(@ApiParam(name="motorId",required=true) @PathVariable Long motorId) {
        //当前电机库版本号加1并同步用户信息
        Long motorV = SecurityUtils.getLoginUser().getUser().getDept().getSyncMotorV() + 1L;
        SysDept sysDept = new SysDept();
        sysDept.setSyncMotorV(motorV);
        sysDept.setDeptId(SecurityUtils.getLoginUser().getUser().getDept().getDeptId());
        sysDeptService.updateDept(sysDept);
        //删除电机库数据
        return AjaxResult.success(kyBaseMotorService.deleteKyBaseMotorByMotorId(motorId));

    }


    /**
     * 上传平板新建的电机库
     *
     * @param padMotorVo
     * code = 610, message = "非法的请求"
     * code = 2012, message = "未注册仪器"
     * @return
     */
    @Transactional
    @Anonymous
    @RateLimiter
    @PostMapping(value = "/motor/create")
    public AjaxResult addMotors(@Validated @RequestBody PadMotorPadToServerDTO padMotorVo) {

        if (!padMotorVo.signOk()) {
            return AjaxResult.error(SystemHttpCode.ERROR_ILLEGAL.getCode(), "非法请求");
        }

        // 根据padSn查询已绑定的平板
        KyPadInfo kyPadInfo = kyPadInfoService.selectKyPadInfoByPadSn(padMotorVo.getPadSn());
        if (kyPadInfo == null) {
            return AjaxResult.error(ServiceHttpCode.BIND_UNBOUND.getCode(), "未注册");
        }

        List<KyBaseMotor> motorVoList = padMotorVo.getMotorList();
        for (KyBaseMotor item : motorVoList) {
            item.setCreateTime(new Date());
            // 0内置  1自定义
            item.setBelongFlag("1");
            item.setDelFlag("0");
            item.setDeptId(kyPadInfo.getDeptId());
            item.setPadSn(kyPadInfo.getPadSn());
        }
        int okCount = kyBaseMotorService.insertKyBaseMotorBatch(motorVoList);
        Map<String, Object> result = MapUtil.newHashMap();
        result.put("okCount", okCount);
        return AjaxResult.success("成功提交" + okCount + "条数据", result);

    }


}
